import 'dart:convert';

import 'package:core/core.dart';
import 'package:core/http/dio_log_interceptor.dart';
import 'package:dio/dio.dart';

class Http {
  static final Http _instance = Http._internal();

  // 单例模式使用Http类，
  factory Http() => _instance;

  static late final Dio dio;
  final CancelToken _cancelToken = CancelToken();

  Options _defaultOptions = Options();

  Http._internal() {
    // BaseOptions、Options、RequestOptions 都可以配置参数，优先级别依次递增，且可以根据优先级别覆盖参数
    BaseOptions options = BaseOptions();

    dio = Dio(options);

    // dio.interceptors.add(LogInterceptor());
    dio.interceptors.add(DioLogInterceptor());
    // // 添加request拦截器
    // dio.interceptors.add(RequestInterceptor());
    // // 添加error拦截器
    // dio.interceptors.add(ErrorInterceptor());
    // // // 添加cache拦截器
    // dio.interceptors.add(NetCacheInterceptor());
    // // // 添加retry拦截器
    // dio.interceptors.add(
    //   RetryOnConnectionChangeInterceptor(
    //     requestRetrier: DioConnectivityRequestRetrier(
    //       dio: dio,
    //       connectivity: Connectivity(),
    //     ),
    //   ),
    // );

    // 在调试模式下需要抓包调试，所以我们使用代理，并禁用HTTPS证书校验
    // if (PROXY_ENABLE) {
    //   (dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
    //       (client) {
    //     client.findProxy = (uri) {
    //       return "PROXY $PROXY_IP:$PROXY_PORT";
    //     };
    //     //代理工具会提供一个抓包的自签名证书，会通不过证书校验，所以我们禁用证书校验
    //     client.badCertificateCallback =
    //         (X509Certificate cert, String host, int port) => true;
    //   };
    // }
  }

  ///初始化公共属性
  ///
  /// [baseUrl] 地址前缀
  /// [connectTimeout] 连接超时赶时间
  /// [receiveTimeout] 接收超时赶时间
  /// [interceptors] 基础拦截器
  void init({
    String? baseUrl,
    int connectTimeout = 2000,
    int receiveTimeout = 2000,
    Map<String, String>? headers,
    List<Interceptor>? interceptors,
  }) {
    dio.options = dio.options.copyWith(
      baseUrl: baseUrl,
      connectTimeout: Duration(milliseconds: connectTimeout),
      receiveTimeout: Duration(milliseconds: receiveTimeout),
      headers: headers ?? const {},
    );
    // 在初始化http类的时候，可以传入拦截器
    if (interceptors != null && interceptors.isNotEmpty) {
      dio.interceptors.addAll(interceptors);
    }
  }

  /// 设置默认options
  void setOptions(Options defaultOptions) {
    _defaultOptions = defaultOptions;
  }

  /// 添加拦截器
  void addInterceptors(List<Interceptor> interceptors) {
    dio.interceptors.addAll(interceptors);
  }

  // 关闭dio
  void cancelRequests({required CancelToken token}) {
    _cancelToken.cancel("cancelled");
  }

  // 添加认证
  // 读取本地配置
  Map<String, dynamic>? getAuthorizationHeader() {
    Map<String, dynamic>? headers;
    // 从getx或者sputils中获取
    // String accessToken = Global.accessToken;
    String accessToken = "";
    headers = {
      'Authorization': 'Bearer $accessToken',
    };
    return headers;
  }

  Future<Map> get(
    String path, {
    Map<String, dynamic>? params,
    Options? options,
    CancelToken? cancelToken,
    bool refresh = false,
    bool noCache = true, // !CACHE_ENABLE,
    String? cacheKey,
    bool cacheDisk = false,
    bool showLoading = true,
  }) async {
    if(showLoading) ToastHelper.loading();
    Options requestOptions = options ?? _defaultOptions;
    requestOptions = requestOptions.copyWith(
      extra: {
        "refresh": refresh,
        "noCache": noCache,
        "cacheKey": cacheKey,
        "cacheDisk": cacheDisk,
      },
    );
    // Map<String, dynamic>? authorization = getAuthorizationHeader();
    // if (authorization != null) {
    //   requestOptions = requestOptions.copyWith(headers: authorization);
    // }
    Response response;
    response = await dio.get(
      path,
      queryParameters: params,
      options: requestOptions,
      cancelToken: cancelToken ?? _cancelToken,
    );
    if(showLoading) ToastHelper.closeLoading();
    return jsonDecode(response.toString());
  }

  Future<Map> post(
    String path, {
    Map<String, dynamic>? params,
    data,
    Options? options,
    CancelToken? cancelToken,
    bool showLoading = true,
  }) async {
    if(showLoading) ToastHelper.loading();
    Options requestOptions = options ?? _defaultOptions;
    // Map<String, dynamic>? authorization = getAuthorizationHeader();
    // if (authorization != null) {
    //   requestOptions = requestOptions.copyWith(headers: authorization);
    // }
    var response = await dio.post(
      path,
      data: data,
      queryParameters: params,
      options: requestOptions,
      cancelToken: cancelToken ?? _cancelToken,
    );
    if(showLoading) ToastHelper.closeLoading();
    return jsonDecode(response.toString());
  }

  Future<Map> put(
    String path, {
    data,
    Map<String, dynamic>? params,
    Options? options,
    CancelToken? cancelToken,
    bool showLoading = true,
  }) async {
    if(showLoading) ToastHelper.loading();
    Options requestOptions = options ?? _defaultOptions;

    // Map<String, dynamic>? authorization = getAuthorizationHeader();
    // if (authorization != null) {
    //   requestOptions = requestOptions.copyWith(headers: authorization);
    // }
    var response = await dio.put(
      path,
      data: data,
      queryParameters: params,
      options: requestOptions,
      cancelToken: cancelToken ?? _cancelToken,
    );
    if(showLoading) ToastHelper.closeLoading();
    return jsonDecode(response.toString());
  }

  Future<Map> patch(
    String path, {
    data,
    Map<String, dynamic>? params,
    Options? options,
    CancelToken? cancelToken,
    bool showLoading = true,
  }) async {
    if(showLoading) ToastHelper.loading();
    Options requestOptions = options ?? _defaultOptions;
    // Map<String, dynamic>? authorization = getAuthorizationHeader();
    // if (authorization != null) {
    //   requestOptions = requestOptions.copyWith(headers: authorization);
    // }
    var response = await dio.patch(
      path,
      data: data,
      queryParameters: params,
      options: requestOptions,
      cancelToken: cancelToken ?? _cancelToken,
    );
    if(showLoading) ToastHelper.closeLoading();
    return jsonDecode(response.toString());
  }

  Future<Map> delete(
    String path, {
    data,
    Map<String, dynamic>? params,
    Options? options,
    CancelToken? cancelToken,
    bool showLoading = true,
  }) async {
    if(showLoading) ToastHelper.loading();
    Options requestOptions = options ?? _defaultOptions;

    // Map<String, dynamic>? authorization = getAuthorizationHeader();
    // if (authorization != null) {
    //   requestOptions = requestOptions.copyWith(headers: authorization);
    // }
    var response = await dio.delete(
      path,
      data: data,
      queryParameters: params,
      options: requestOptions,
      cancelToken: cancelToken ?? _cancelToken,
    );
    if(showLoading) ToastHelper.closeLoading();
    return jsonDecode(response.toString());
  }
}
